use std::collections::HashMap;
use std::error::Error;
use std::net::{IpAddr, Ipv4Addr};
use async_trait::async_trait;
use local_ip_address::local_ip;
use redis::aio::MultiplexedConnection;
use sea_orm::{DatabaseConnection, EntityTrait, Set};
use snowid::SnowID;
use tracing::warn;
use crate::entity::{sys_scheduled_task, sys_scheduled_task_execution_log};
use crate::scheduler::task::order_timeout_cancellation_task::OrderTimeoutCancellationTask;

pub struct ExecuteResult {
    pub code: u8,
    pub total_count: u32,
    pub success_count: u32,
    pub fail_count: u32,
    pub error_message: Option<String>,
}


// 任务 trait
#[async_trait]
pub trait DynamicTask: Send + Sync {
    async fn execute(
        &self,
        db: DatabaseConnection,
        conn: MultiplexedConnection,
        task_parameter: Option<String>)
        -> Result<ExecuteResult, Box<dyn Error>>;
}

// 定义任务函数类型
type TaskFn = fn() -> Result<(), Box<dyn Error>>;

pub struct DynamicTaskScheduler {
    db: DatabaseConnection,
    conn: MultiplexedConnection,
    task: sys_scheduled_task::Model,
    registry: HashMap<String, Box<dyn DynamicTask>>,
}

impl DynamicTaskScheduler {
    pub fn new(db: DatabaseConnection, conn: MultiplexedConnection, task: sys_scheduled_task::Model) -> Self {

        let mut method = HashMap::<String, Box<dyn DynamicTask>>::new();

        method.insert("OrderTimeoutCancellationTask".to_string(), Box::new(OrderTimeoutCancellationTask));

        Self { db, conn, task, registry: method}
    }

    pub async fn exec(&self) {

        loop {
            // 执行任务
            match self.registry.get(&self.task.task_name) {
                Some(task) => {

                    
                    let start_time = chrono::Utc::now().naive_utc();
                    let mut result_code = 0u8;
                    let mut error_message = None;
                    let sn = SnowID::new(1).unwrap();
                    // 记录任务开始执行
                    let log_model = sys_scheduled_task_execution_log::ActiveModel {
                        id: Set(sn.generate()),
                        task_id: Set(self.task.id),
                        start_time: Set(start_time),
                        end_time: Set(start_time), // 先设置默认值
                        duration_ms: Set(0),
                        result_code: Set(0), // 先设置默认值
                        error_message: Set(None),
                        host_ip: Set(local_ip().unwrap_or(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0))).to_string()),
                    };

                    let log_entry = sys_scheduled_task_execution_log::Entity::insert(log_model)
                        .exec_with_returning(&self.db)
                        .await
                        .expect("创建任务日志失败");



                    task.execute(self.db.clone(), self.conn.clone(), self.task.task_parameter.clone()).await;


                    let end_time = chrono::Utc::now().naive_utc();
                    let duration_ms = (end_time.and_utc().timestamp_millis() - start_time.and_utc().timestamp_millis()) as u32;

                    // 更新日志记录
                    let mut log_active: sys_scheduled_task_execution_log::ActiveModel = log_entry.into();
                    log_active.end_time = Set(end_time);
                    log_active.duration_ms = Set(duration_ms);
                    log_active.result_code = Set(result_code);
                    log_active.error_message = Set(error_message);

                    sys_scheduled_task_execution_log::Entity::update(log_active)
                        .exec(&self.db)
                        .await
                        .expect("更新任务日志失败");



                    let mut task_active: sys_scheduled_task::ActiveModel = self.task.clone().into();
                    task_active.last_run_time = Set(Some(end_time));
                    task_active.next_run_time = Set(end_time + chrono::Duration::minutes(5)); // 5分钟后再次执行
                    task_active.update_time = Set(end_time);

                    sys_scheduled_task::Entity::update(task_active)
                        .exec(&self.db)
                        .await
                        .expect( "更新任务信息失败");
                }

                None => warn!("Task '{}' not found", &self.task.task_name),
            };

        }
    }
}

